﻿#include "stdafx.h" //
#include "my_global.h" // Include this file first to avoid problems
#include "mysql.h" // MySQL Include File

#define WIN32
/*#define LINUX*/

#ifdef WIN32
#include <windows.h>
#include <winsock.h>
#pragma comment(lib, "wsock32.lib")
#define BUILD_TYPE "WIN32"

#endif

#ifdef LINUX
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define BUILD_TYPE "LINUX"
#endif

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <string>
#include <sstream>
#include <malloc.h>
#include <stdarg.h>

using namespace std;

#define IRC_BUFFER_SIZE 512
#define MAX_ARGS        256
#define SERVER "localhost"
#define USER "neoph-"
#define PASSWORD "prier"
#define DATABASE "valhalla"


#ifdef WIN32
#define vsnprintf _vsnprintf
#define snprintf  _snprintf
#endif


/********************************************************************\
  IRC_CLIENT CONFIGURATION
\********************************************************************/
const char *IRC_SERVER   = "se.quakenet.org";
const short IRC_PORT     = 6667;
const char *IRC_CHAN     = "#afterlife";
const char *IRC_CHANKEY  = "key";
const char *IRC_NICK     = "al-Support";
const char *IRC_REALNAME = "Afterlife support bot";
const char *USER_NICK;
const char *USER_AUTH;
const char *USER_ARG;
string user("");
string auth("");
string argumentos("");
string argcheck("");
bool stats = false;
bool vouchme = false;
bool vouch = false;
const char IRC_CMD_TRIGGER = '.';
MYSQL *conn; // Create a pointer to the MySQL instance

/********************************************************************\
  COMMAND PROTOTYPES
\********************************************************************/

void cmd_quit(int sock, char *from_p, char **arg_p, int arg_count),
     cmd_test(int sock, char *from_p, char **arg_p, int arg_count),
	 cmd_server(int sock, char *from_p, char **arg_p, int arg_count),
	 cmd_stats(int sock, char *from_p, char **arg_p, int arg_count),
	 cmd_vouch(int sock, char *from_p, char **arg_p, int arg_count),
	 cmd_cl(int sock, char *from_p, char **arg_p, int arg_count),
	 cmd_sign(int sock, char *from_p, char **arg_p, int arg_count),
	 cmd_vouchme(int sock, char *from_p, char **arg_p, int arg_count),
     cmd_help(int sock, char *from_p, char **arg_p, int arg_count);

char* convert(const std::string& str);
void do_vouchme(int sock);
void do_vouch(int sock);
void do_cl(int sock);
void do_stats(int sock);

/********************************************************************\
  FUNCTION PROTOTYPES
\********************************************************************/
int irc_connect(int sock, const char *remote_host_p, unsigned short remote_port),
    irc_send_line(int sock, const char *format_p, ...),
    irc_recv_line(int sock, char *line_p, unsigned int line_size);

/* this is pretty much just a table of
   command names and pointers to their according functions */
struct irc_command
{
   const char *command_name_p,
              *description_p;
   void (*exec_command)(int sock, char *from_p, char **arg_p, int arg_count);
}

/********************************************************************\
  COMMAND TABLE
\********************************************************************/
COMMAND[] =
{
   {"quit", "Make the bot quit",               &cmd_quit},
   {"test", "A test command",                  &cmd_test},
   {"server", "Show cs server information",    &cmd_server},
   {"stats", "Show stats of a user",           &cmd_stats},
   {"vouchme", "vouches a user",               &cmd_vouchme},
   {"vouch", "vouches a specified user",       &cmd_vouch},
   {"cl", "challenge a specified user",        &cmd_cl},
   {"sign", "signup for current gather",       &cmd_sign},
   {"help", "Print this menu",                 &cmd_help}
};


/********************************************************************\
  BOT MAIN
\********************************************************************/
int main(int argc, char **argv)
{
	// Mysql connection

    conn=mysql_init(NULL); // Initialise the instance
    /* This If is irrelevant and you don't need to show it. I kept it in for Fault Testing.*/
    if(!connect)    /* If instance didn't initialize say so and exit with fault.*/
    {
        fprintf(stderr,"MySQL Initialization Failed");
        //return 1;
    }
    /* Now we will actually connect to the specific database.*/
 
    conn=mysql_real_connect(conn,SERVER,USER,PASSWORD,DATABASE,0,NULL,0);
    /* Following if statements are unneeded too, but it's worth it to show on your
    first app, so that if your database is empty or the query didn't return anything it
    will at least let you know that the connection to the mysql server was established. */
 
    if(conn){
        printf("Connection Succeeded\n");
    }
    else{
        printf("Connection Failed!\n");
    }

	mysql_query(conn, "SET sql_mode='NO_BACKSLASH_ESCAPES'");

#ifdef WIN32
   WSADATA wsa_data; /* a structure to store output from the WSAStartup call,
                        we dont do anything with this so just ignore it */
#endif
   int     sock,     /* our socket handle */
           connect_attempts = 0,
           argument_count,
           i;
   char    buffer[512]      = {0}, /* buffer to recv lines from IRC */
           from[56]         = {0},
           nick[56]         = {0},
           *argument[MAX_ARGS],
		   *cust[MAX_ARGS],
           *token_p;


#ifdef WIN32
   /* WSAStartup() initializes the WinSock DLL, version 2.2,
      MAKEWORD(2, 2) just takes 2 bytes each with a value of 2 (00000010)
      and puts them together like so (0000001000000010),
      ^^ this isn't really important so you can ignore this */
   if (WSAStartup(MAKEWORD(2, 2), &wsa_data))
   {
      printf("- fatal error: failed to initialize winsock\r\n");
      return (0);                         
   }
#endif

   /* create a socket using the INET protocol family (IPv4),
      and make it a streaming TCP socket */
   if ((sock = socket(PF_INET,
                      SOCK_STREAM,
                      IPPROTO_TCP)) == -1)
   {
      printf("- fatal error: socket() failed.\r\n");
      return (0);                 
   }

   printf("- Created socket\r\n");

   if (!irc_connect(sock, IRC_SERVER, IRC_PORT))
   {
      printf("- Failed to connect to %s:%i\r\n", IRC_SERVER, IRC_PORT);
      return (0);               
   }

   printf("- Connected to %s:%i\r\n", IRC_SERVER, IRC_PORT);

   snprintf(nick, sizeof(nick), "%s", IRC_NICK);

   irc_send_line(sock, "USER %s 127.0.0.1 localhost :%s", IRC_NICK, IRC_REALNAME);
   irc_send_line(sock, "NICK %s", nick);

   while (1)
   {
      memset(buffer, 0, sizeof(buffer));

      if (irc_recv_line(sock, buffer, sizeof(buffer)) == 0)
         break;

      token_p = strtok(buffer, " ");
      argument_count = 0;

      while (token_p != NULL)
      {
         argument[argument_count] = token_p;
         token_p = strtok(NULL, " ");
         argument_count++;
      }

      if (argument_count > 2)
      {
         if (strcmp(argument[1], "001") == 0)
         {
            irc_send_line(sock, "JOIN %s :%s", IRC_CHAN, IRC_CHANKEY);
            continue;                   
         }                   

         else if (strcmp(argument[1], "433") == 0)
         {
            strncat(nick, "_", 1);
            irc_send_line(sock, "NICK %s", nick);
            continue;     
         }

		 
      }

      if (argument_count == 2)
      {
         if (strcmp(argument[0], "PING") == 0)
         {
            irc_send_line(sock, "PONG %s", argument[1]);
            continue;                     
         }                   
      }

      if (argument_count >= 4)
      {
		 if (strcmp(argument[1], "330") == 0)
         {
			USER_AUTH = argument[4];
			auth = argument[4];

			if (vouchme == true)
			{
				do_vouchme(sock);
			}
			else if (vouch == true)
			{
				do_vouch(sock);
			}
			else if (stats == true)
			{
				do_stats(sock);
			}
            
			continue;     
         }

         if (strcmp(argument[1], "PRIVMSG") == 0)
         {
            snprintf(from, sizeof(from), "%s", argument[2]);

			string s = argument[0]+1; // Remove colon ':' in front
			
		    string::size_type prev_pos = 0, pos = 0;

			while( (pos = s.find('!', pos)) != std::string::npos )
			{
				string substring( s.substr(prev_pos, pos-prev_pos) );

				user = substring;
				USER_NICK = convert(substring); // Get nick of user who fired the command
				prev_pos = ++pos;
			}

            /* this just shifts the argument variable the
               numbers of bytes there are before the PRIVMSG text
               so ":user@host PRIVMSG #channel :message here"
               becomes just "message here" */

            if (argument[3][1] == IRC_CMD_TRIGGER)
            {   
               *argument += (strlen(argument[0]) + 1) +
                            (strlen(argument[1]) + 1) +
                            (strlen(argument[2]) + 3);

               for (i = 0; i < sizeof(COMMAND) / sizeof(struct irc_command); ++i)
               {
                  if (strcmp(argument[0], COMMAND[i].command_name_p) == 0)
                  {
					 argumentos = argument[4];
                     COMMAND[i].exec_command(sock, from, argument, argument_count - 3);
                     break;                         
                  }
               }
            }

            continue;                         
         }

      }
   }

   printf("- Disconnected\r\n");

#ifdef WIN32
   /* clean up after ourselves */
   WSACleanup();
#endif
   return (0);
}

/********************************************************************\
  CONVERT FUNCTION
\********************************************************************/

char* convert(const std::string& str) {
    char* result = new char[str.length()+1];
    strcpy(result,str.c_str());
    return result;
}

/********************************************************************\
  IRC CONNECT FUNCTION
\********************************************************************/
int irc_connect(int sock, const char *remote_host_p, unsigned short remote_port)
{
   struct sockaddr_in sin;        /* a structure which tells our socket where it's connecting to */
   struct hostent     *hostent_p; /* a structure which will store results from the DNS query we do
                                     for remote_host_p */

   /* perform a DNS query to find the IP address of remote_host_p */
   if (!(hostent_p = gethostbyname(remote_host_p)))
      return (0);           

   memset(&sin, 0, sizeof(sin));
   sin.sin_family = PF_INET; /* IPv4 */
   sin.sin_addr.s_addr = *(long *) hostent_p->h_addr; /* take the IP address returned */
   sin.sin_port = htons(remote_port); /* convert remote_port to a network order byte */

   printf("- Resolved %s to %s\r\n", remote_host_p, inet_ntoa(sin.sin_addr));

   /* tell the socket to connect */
   if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1)
      return (0);

   return (1);
}

/********************************************************************\
  IRC SEND LINE FUNCTION
\********************************************************************/
int irc_send_line(int sock, const char *format_p, ...)
{
   va_list args;
   char    buffer[512] = {0};

   va_start(args, format_p);
   vsnprintf(buffer, sizeof(buffer), format_p, args);
   va_end(args);

   strncat(buffer, "\r\n", (sizeof(buffer) - strlen(buffer)));

   printf(">> %s", buffer);

   return (send(sock, buffer, strlen(buffer), 0));
}

/********************************************************************\
  IRC RECIEVE LINE FUNCTION
\********************************************************************/
int irc_recv_line(int sock, char *line_p, unsigned int line_size)
{
   char byte = 0;
   /* recv one byte at a time from the socket
      untill you reach a newline (\n) character */

   while (byte != '\n' && strlen(line_p) < line_size)
   {
      if (!recv(sock, (char *) &byte, 1, 0))
         return (0);

      if (byte != '\r' && byte != '\n' && byte != '\0')
      {       
         strncat(line_p, (char *) &byte, 1);
      }
   }

   printf("<< %s\r\n", line_p);
   return (1);
}

/********************************************************************\
  QUIT COMMAND FUNCTION
\********************************************************************/
void cmd_quit(int sock, char *from_p, char **arg_p, int arg_count)
{	
	if(user == "neoph-")
	{
		//irc_send_line(sock, "TOPIC %s :%s", IRC_CHAN, IRC_TOPIC2);
		irc_send_line(sock, "QUIT");
	}
	else
	{
		irc_send_line(sock, "PRIVMSG %s :%c4»%c You %s are not neoph! ", IRC_CHAN, 3, 3, USER_NICK);
	}
}

/********************************************************************\
  SERVER COMMAND FUNCTION
\********************************************************************/
void cmd_server(int sock, char *from_p, char **arg_p, int arg_count)
{
    irc_send_line(sock, "PRIVMSG %s :%c4»%c [valhalla cw] %c4»%c IP: DSRack.com:27935 %c4»%c PW: lol", from_p, 3, 3, 3, 3, 3, 3);
}

/********************************************************************\
  STATS COMMAND FUNCTION
\********************************************************************/
void cmd_stats(int sock, char *from_p, char **arg_p, int arg_count)	
{
	stats = true;
	if (argumentos != ":.stats" || "halla" || "valhalla")
	{
		USER_ARG = convert(argumentos);
		irc_send_line(sock, "WHOIS %s", USER_ARG);
	}
	else 
	{
		irc_send_line(sock, "WHOIS %s", USER_NICK);
	}
}

void do_stats(int sock)
{
	MYSQL_RES *result;
    MYSQL_ROW row;
	string sqlQuery;

	sqlQuery = "SELECT * FROM users WHERE Auth='"+auth+"'";

	mysql_query(conn, sqlQuery.c_str());

	result = mysql_store_result(conn);

	row = mysql_fetch_row(result);

	if (row != NULL)
	{
		irc_send_line(sock, "PRIVMSG %s :%c4»%c %s got %s wins and %s losses %c4»%c EXP: %s", IRC_CHAN, 3, 3, row[1], row[3], row[4], 3, 3, row[5]);
	}
	stats = false;
	argumentos = "";
}

/********************************************************************\
  TEST COMMAND FUNCTION
\********************************************************************/
void cmd_test(int sock, char *from_p, char **arg_p, int arg_count)
{
    irc_send_line(sock, "PRIVMSG %s :This is a test. Did it work?", from_p);
}

/********************************************************************\
  CHALLENGE COMMAND FUNCTION
\********************************************************************/
void cmd_cl(int sock, char *from_p, char **arg_p, int arg_count)
{
    irc_send_line(sock, "PRIVMSG %s :This is a test. Did it work?", from_p);
}

/********************************************************************\
  SIGNUP COMMAND FUNCTION
\********************************************************************/
void cmd_sign(int sock, char *from_p, char **arg_p, int arg_count)
{
	irc_send_line(sock, "PRIVMSG %s :%c4»%c %s has signed in", from_p, 3, 3, USER_NICK);
    
}

/********************************************************************\
  VOUCHME COMMAND FUNCTION
\********************************************************************/
void cmd_vouchme(int sock, char *from_p, char **arg_p, int arg_count)
{
    vouchme = true;
    irc_send_line(sock, "WHOIS %s", USER_NICK);
}

void do_vouchme(int sock)
{
   if(auth != "")
   {
		USER_AUTH = convert(auth);
		ostringstream query;
		query << "INSERT INTO users VALUES('" << auth << "','" << user << "','1','0','0','1000')";
		mysql_query(conn, query.str().c_str());
		irc_send_line(sock, "PRIVMSG %s :%c4»%c %s has been vouched with the username %s", IRC_CHAN, 3, 3, USER_NICK, USER_NICK);
   }
   else
   {
		irc_send_line(sock, "PRIVMSG %s :%c4»%c %s must be authed with Q to use the service!", IRC_CHAN, 3, 3, USER_NICK);
   }
   vouchme = false;
}

/********************************************************************\
  VOUCH COMMAND FUNCTION
\********************************************************************/
void cmd_vouch(int sock, char *from_p, char **arg_p, int arg_count)
{
    vouch = true;
	USER_ARG = convert(argumentos);
    irc_send_line(sock, "WHOIS %s", USER_ARG);
}

void do_vouch(int sock)
{
   if(auth != "")
   {
		USER_NICK = convert(argumentos);
		user = argumentos;
		ostringstream query;
		query << "INSERT INTO users VALUES('" << auth << "','" << user << "','1','0','0','1000')";
		mysql_query(conn, query.str().c_str());
		irc_send_line(sock, "PRIVMSG %s :%c4»%c %s has been vouched with username %s", IRC_CHAN, 3, 3, USER_NICK, USER_NICK);
   }
   else
   {
		irc_send_line(sock, "PRIVMSG %s :%c4»%c %s must be authed with Q to use this service!", IRC_CHAN, 3, 3, USER_NICK);
   }
   vouch = false;
}

/********************************************************************\
  HELP COMMAND FUNCTION
\********************************************************************/
void cmd_help(int sock, char *from_p, char **arg_p, int arg_count)
{
   unsigned int i;

   irc_send_line(sock, "PRIVMSG %s :%c4»%c (Help): Build type: %s (%s, %s)", from_p, 3, 3, BUILD_TYPE, __DATE__, __TIME__);
   irc_send_line(sock, "PRIVMSG %s :%c4»%c (Help): COMMAND   DESCRIPTION", from_p, 3, 3);

   for (i = 0; i < sizeof(COMMAND) / sizeof(struct irc_command); ++i)
   {
      irc_send_line(sock, "PRIVMSG %s :%c4»%c (Help): %s  %s", from_p, 3, 3, COMMAND[i].command_name_p,COMMAND[i].description_p);
   }
   
}